package com.jeebey.mybatis.interceptor;

import java.util.Properties;
import java.util.Set;

import org.apache.ibatis.executor.CachingExecutor;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Plugin;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import com.jeebey.mybatis.utils.CascadeCacheUtil;

/**
 * 缓存清理插件
 * @since 1.0
 * @author <a href="mailto:84961426@qq.com">JuST4iT</a>
 * @version $Id: CacheInterceptor.java Feb 18, 2016 6:05:29 PM $
 */

@Intercepts({
		@Signature(type = Executor.class, method = "query", args = { MappedStatement.class, Object.class,RowBounds.class, ResultHandler.class }),
		@Signature(type = Executor.class, method = "update", args = { MappedStatement.class, Object.class }) })
public class CacheInterceptor implements Interceptor {

	public Object intercept(Invocation invocation) throws Throwable {
		Object targetObject=invocation.getTarget();
		MetaObject executorMetaObject = MetaObject.forObject(targetObject, new DefaultObjectFactory(),new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
		while (executorMetaObject.hasGetter("h")||executorMetaObject.hasGetter("target")) {
			Object _hTargetObj=executorMetaObject.hasGetter("h")?executorMetaObject.getValue("h"):null;
			Object _tTargetObj=executorMetaObject.hasGetter("target")?executorMetaObject.getValue("target"):null;
			targetObject = _hTargetObj!=null?_hTargetObj:_tTargetObj;
			executorMetaObject = MetaObject.forObject(targetObject, new DefaultObjectFactory(),new DefaultObjectWrapperFactory(),new DefaultReflectorFactory());
		}
		
		if (targetObject instanceof CachingExecutor) {
			final MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];

			if (!mappedStatement.getConfiguration().isCacheEnabled() || !mappedStatement.isUseCache()){
				return invocation.proceed();
			}
			  
			//method1:
//	        String mappedStatementId = mappedStatement.getId();  
//	        String nameSpace = mappedStatementId.substring(0, mappedStatementId.lastIndexOf(".")); 
//	        Cache cache = mappedStatement.getConfiguration().getCache(nameSpace);  
	        
			if(mappedStatement.getSqlCommandType()==SqlCommandType.SELECT){
				// CachingExecutor cachingExecutor = (CachingExecutor) targetObject;  
                // Object parameterObject = invocation.getArgs()[1]; 
                // RowBounds rowBounds = (RowBounds) invocation.getArgs()[2]; 
                // BoundSql boundSql=mappedStatement.getBoundSql(parameterObject);
                // CacheKey cacheKey = cachingExecutor.createCacheKey(mappedStatement, parameterObject, rowBounds,boundSql);  
                // cache.removeObject(cacheKey);   清理掉缓存
                // System.out.println("===>"+SqlExecutorUtil.removeBreakingWhitespace(cacheKey.toString()));
			}else{
				String cacheKey = mappedStatement.getCache().getId();
			    //Cache cache = mappedStatement.getCache();
				if(CascadeCacheUtil.cascade_cache.size()==0){
					CascadeCacheUtil.initCascadeCache(cacheKey,mappedStatement.getConfiguration().getCacheNames());
				}
				Set<String> cascades=CascadeCacheUtil.cascade_cache.get(cacheKey);
				if(cascades!=null){
					for(String cascade:cascades){
						 mappedStatement.getConfiguration().getCache(cascade).clear(); 
					}
				}
			}
		}
		return invocation.proceed();
	}

	public Object plugin(Object arg0) {
		return Plugin.wrap(arg0, this);
	}

	@Override
	public void setProperties(Properties arg0) {
	}

}
